package com.ck.framework.aop;

import com.alibaba.fastjson.JSON;
import com.ck.common.bean.AuthResp;
import com.ck.common.bean.McApiResp;
import com.ck.common.constant.Constants;
import com.ck.common.entity.SysLogininfor;
import com.ck.common.exception.BusinessException;
import com.ck.common.utils.ip.IpUtils;
import com.ck.common.utils.jwt.RedisCache;
import com.ck.common.utils.security.RsaUtil;
import com.ck.common.utils.security.sign.CtAes;
import com.ck.common.utils.txt.TextUtil;
import com.ck.common.vo.RSALoginVo;
import com.ck.common.vo.LoginUserVo;
import com.ck.system.service.SysLogininforService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author ck
 * @date 2024/1/19 17:07
 * desc:登录日志记录
 */

@Slf4j
@Aspect
@Component
public class RsaLoginAspect {
    private static String isDebug;

    @Value("${isDebug}")
    public void setProfile(String pro) {
        isDebug = pro;
    }


    @Autowired
    RedisCache redisCache;

    @Autowired
    SysLogininforService sysLogininforService;

    @Pointcut("execution(* com.ck.server.controller.test.login.RsaAndAesLoginController.login(..))")
    private void loginPointCut() {
    }

    @Before(value = "loginPointCut()")
    public void doBefore(JoinPoint joinPoint){
        log.info("用户登录");
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        args.forEach(arg -> {
            if (arg instanceof RSALoginVo){
                RSALoginVo rsaLoginVo = (RSALoginVo) arg;
                log.info("登录信息:{}", JSON.toJSONString(rsaLoginVo));
                String keyId = rsaLoginVo.getKeyId();
                String data = rsaLoginVo.getD();
                Assert.notNull(data,"登录信息输入错误");
                Assert.notNull(keyId, "登录keyId错误");

                //开始解密
                try {
                    String decryptData = RsaUtil.decryptReqDataLogin(data, keyId,redisCache);
                    rsaLoginVo.setD(decryptData);
                    arg = rsaLoginVo;
                } catch (Exception e) {
                    log.error("登录解密错误:{}", TextUtil.ex2Txt(e));
                    throw new BusinessException("登录异常");
                }
            }
        });
    }

    /**返回通知, 在方法返回结果之后执行*/
    @AfterReturning(pointcut = "loginPointCut()", returning = "result")
    public Object doAfterLogin(JoinPoint joinPoint,Object result){
        return loginLog(null,result);
    }

    /**异常通知, 在方法抛出异常之后*/
    @AfterThrowing(pointcut = "loginPointCut()", throwing = "ex")
    public void doAfterLogin(JoinPoint joinPoint, Exception ex) {
        loginLog(ex, null);
    }

    private Object loginLog(Exception e, Object result) {
        SysLogininfor loginInfo = new SysLogininfor();
        loginInfo.setLoginTime(new Date());
        loginInfo.setIpaddr(IpUtils.getIpAddr());
        String username = null;
        //获取当前用户信息
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof LoginUserVo) {
            LoginUserVo loginUser = (LoginUserVo) principal;
            username = loginUser.getUsername();
        }
        if (null == e) {
            loginInfo.setStatus(Constants.SUCCESS);
            McApiResp resp = (McApiResp) result;
            if (resp.getCode().equals(Constants.SUCCESS)) {
                loginInfo.setUserName(username);
                loginInfo.setMsg(Constants.LOGIN_SUCCESS);
                //加密
                if (!"Y".startsWith(isDebug)) {
                    try {
                        Map<String, Object> retMap = (Map<String, Object>) resp.getRetData();
                        AuthResp data = (AuthResp) retMap.get("data");
                        //偏移量
                        String vipara = data.getVipara();
                        //Aes秘钥
                        String aesKey = data.getAesKey();
                        //设置登录成功后返回给前端的数据(加密后的(AES))
                        resp.setRetData(RsaUtil.encodeRespData(JSON.toJSONString(data), new CtAes(vipara, aesKey), null, redisCache));
                    } catch (Exception ex) {
                        log.info("登录返回数据加密错误:{}", TextUtil.ex2Txt(ex));
                    }
                }
            } else {
                loginInfo.setUserName(username);
                loginInfo.setMsg("鉴权失败");
            }
        } else {
            loginInfo.setStatus(Constants.FAIL);
            loginInfo.setMsg("登录失败," + e.getMessage());
        }
        log.info("用户:{} 登录成功:{}", username, JSON.toJSONString(loginInfo));
        sysLogininforService.insertLogininfor(loginInfo);
        return result;
    }
}

